<?php

namespace addons\zzyy\module;

use addons\zzyy\library\AesUtil;
use addons\zzyy\library\SaasCenter;
use EasyWeChat\Factory;
use fast\Http;
use function EasyWeChat\Kernel\Support\get_client_ip;


final class Weixin
{
    protected static  $_instance =null;

    protected $_ispInfo = null;

    private function __construct()
    {
        $this->_ispInfo = SaasCenter::getOpenPlatformMerchantIsp();
    }

    private function __clone()
    {

    }

    public static function getInstance()
    {
        if (self::$_instance == null){

            self::$_instance = new self();
        }
        return self::$_instance;
    }

    public function getSession($code)
    {
        $addonConfig = get_addon_config('zzyy');

        //如果是独立部署的
        if (isset($addonConfig['is_independent_app']) and 1 == $addonConfig['is_independent_app']) {

            $config = [
                'app_id' => $addonConfig['mp_appid'],
                'secret' => $addonConfig['mp_app_secret'],
                'response_type' => 'array',
                'log' => [
                    'level' => 'debug',
                    'file' =>  LOG_PATH. '/wechat.log',
                ],
            ];

            return Factory::miniProgram($config)->auth->session($code);;

        } else {

            $appletId = $addonConfig['saas_applet_id'];
            $data = SaasCenter::getOpenPlatformInfoAndRefreshToken($appletId);

            $headers = ['Content-Type: application/json'];
            $options = [
                CURLOPT_HTTPHEADER => $headers
            ];

            $url = 'https://api.weixin.qq.com/sns/component/jscode2session';
            $params = [
                'component_access_token' => $data['component_access_token'],
                'appid' => $addonConfig['mp_appid'],
                'grant_type' => 'authorization_code',
                'component_appid' => $data['app_id'],
                'js_code' => $code,
            ];

            $result = json_decode(Http::get($url, $params, $options), true);

            return $result;
        }
    }


    public function jsapi($out_trade_no, $total,$openid, $notify_url, $attach='订单支付')
    {
        $params = [
            'description' => $attach,//商品描述
            'attach' => $attach,//附加数据
            'out_trade_no' => $out_trade_no,//商户订单号
            'notify_url' => $notify_url, //通知地址
            'amount' => [
                'total' => intval($total * 100),//订单总金额，单位为分
            ],
            'scene_info' => [
                'payer_client_ip' => get_client_ip(),//用户终端IP
            ],
        ];

        $addonConfig = get_addon_config('zzyy');

        if ($addonConfig['is_normal_merchant'] == 0) {
            //服务商
            $params['sp_appid'] = $this->_ispInfo['app_id'];//服务商应用ID
            $params['sp_mchid'] = $this->_ispInfo['mch_id'];//服务商商户号
            $params['sub_appid'] = $addonConfig['mp_appid'];//子商户应用ID
            $params['sub_mchid'] = $addonConfig['pay_sub_merchant_id'];//子商户号
            $params['payer']['sub_openid'] = $openid; //子用户标识Openid
            $url = 'https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi';//服务商
            $is_isp = true;
        } else {
            //直连商户
            $params['appid'] = $addonConfig['mp_appid'];//小程序ID
            $params['mchid'] = $addonConfig['pay_merchant_id'];//商户号
            $params['payer']['openid'] = $openid; //用户标识Openid
            $url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi'; //直连商户
            $is_isp = false;
        }
        $params = json_encode($params, JSON_UNESCAPED_UNICODE);
        $headers = [
            'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params,$is_isp),
            'Content-Type:application/json',
            'Accept:application/json',
            'User-Agent:' . $is_isp ? $this->_ispInfo['mch_id'] : $addonConfig['pay_merchant_id'],
        ];
        $options = [
            CURLOPT_HTTPHEADER => $headers
        ];
        $result = json_decode(Http::post($url, $params, $options),true);

        if(isset($result['code'])){
            throw new \Exception('code：' . $result['code'] . '，msg：' . $result['message']);
        }
        if(!isset($result['prepay_id'])){
            throw new \Exception('JSAPI下单接口请求失败');
        }
        $data = [
            'timeStamp' => (string)time(),
            'nonceStr' => $this->nonce(),
            'package' => 'prepay_id=' . $result['prepay_id'],
            'signType' => 'RSA',
        ];
        $data['paySign'] = $this->paySign($data);
        return $data;
    }

    public function notify()
    {
        //接收微信服务器回调的数据流
        if (!$json = file_get_contents('php://input')) {
            return false;
        }
        // 将服务器返回的json数据转化为数组
        $result = json_decode($json,true);

        $addonConfig = get_addon_config('zzyy');
        if ($addonConfig['is_normal_merchant'] == 0) {
            //服务商
            $api_key = $this->_ispInfo['api_key'];
        }else{
            //直连商户
            $api_key = $addonConfig['pay_api_key'];
        }
        if(!$decrypt = new AesUtil($api_key)){
            return false;
        }
        if(!$res = $decrypt->decryptToString($result['resource']['associated_data'], $result['resource']['nonce'], $result['resource']['ciphertext'])){
            return false;
        }
        $array = json_decode($res,true);

        return $array;
    }

    public function refunds($transaction_id,$out_refund_no,$refund_fee,$total_fee)
    {
        $params = [
            'transaction_id' => $transaction_id,//微信支付订单号
            'out_refund_no' => $out_refund_no,//退款订单号
            'amount' => [
                'refund' => intval($refund_fee * 100), // 退款金额，价格:单位分
                'total' => intval($total_fee * 100), // 订单金额，价格:单位分
                'currency' => 'CNY', //退款币种 只支持人民币：CNY
            ],
        ];
        $addonConfig = get_addon_config('zzyy');
        if ($addonConfig['is_normal_merchant'] == 0) {
            //服务商
            $params['sub_mchid'] = $addonConfig['pay_sub_merchant_id'];//子商户号
            $is_isp = true;
        }else{
            $is_isp = false;
        }

        $params = json_encode($params, JSON_UNESCAPED_UNICODE);
        $url = 'https://api.mch.weixin.qq.com/v3/refund/domestic/refunds';
        $headers = [
            'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $this->sign($url,'POST',$params, $is_isp),
            'Content-Type:application/json',
            'Accept:application/json',
            'User-Agent:' . $is_isp ? $this->_ispInfo['mch_id']:$addonConfig['pay_merchant_id'],
        ];
        $options = [
            CURLOPT_HTTPHEADER => $headers
        ];

        $result = json_decode(Http::post($url, $params, $options),true);
        if(isset($result['code'])){
            throw new \Exception('code：' . $result['code'] . '，msg：' . $result['message']);
        }

        return $result;
    }


    private function sign($url, $http_method, $body='',$is_isp=true)
    {
        $timestamp = time(); //时间戳
        $nonce = $this->nonce(); //随机字符串
        $url_parts = parse_url($url);
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        $params = $http_method . "\n" .
            $canonical_url . "\n" .
            $timestamp . "\n" .
            $nonce . "\n" .
            $body . "\n";
        if($is_isp){
            $mchid = $this->_ispInfo['mch_id']; //商户号
            $serial_no = $this->_ispInfo['api_serial_no']; //API证书序列号
            $mch_private_key = $this->_ispInfo['key_pem']; //API私有证书
        }else{
            $addonConfig = get_addon_config('zzyy');
            $mchid = $addonConfig['pay_merchant_id']; //商户号
            $serial_no = $addonConfig['pay_api_serial_no']; //API证书序列号
            $mch_private_key = $addonConfig['pay_key_file']; //API私有证书
        }
        $raw_sign = '';
        openssl_sign($params, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
        $sign = base64_encode($raw_sign);
        //$schema = 'WECHATPAY2-SHA256-RSA2048';
        $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',$mchid, $nonce, $timestamp, $serial_no, $sign);
        return $token;
    }

    private function nonce()
    {
        return md5(uniqid());
    }

    /**
     * 调起支付签名
     */
    private function paySign($data)
    {
        $addonConfig = get_addon_config('zzyy');
        $params = $addonConfig['mp_appid'] . "\n" .
            $data['timeStamp'] . "\n" .
            $data['nonceStr'] . "\n" .
            $data['package'] . "\n";
        if ($addonConfig['is_normal_merchant'] == 0) {
            //服务商
            $private_key = $this->_ispInfo['key_pem']; //API私有证书
        }else{
            //直连商户
            $private_key = $addonConfig['pay_key_file']; //API私有证书
        }
        $raw_sign = '';
        openssl_sign($params, $raw_sign, $private_key, 'sha256WithRSAEncryption');
        return base64_encode($raw_sign);
    }

    /**
     * 返回状态给微信服务器
     */
    public function returnHttpCode($is_success = true, $msg = '失败')
    {
        $json = json_encode([
            'code' => $is_success ? 'SUCCESS' : 'FAIL',
            'message' => $is_success ? '成功' : $msg,
        ], JSON_UNESCAPED_UNICODE);
        if($is_success){
            header('HTTP/1.1 200 OK');
        }else{
            header('HTTP/1.1 404 Not Found');
        }
        die($json);
    }


}